//{==================================================================================================
//! @file NormalizeSqrt.cpp
//! @date 2013-09-29
//! @mainpage Programm for "normalize" sqrt, (sqrt(n)=b*sqrt(a)), Yb' > b : sqrt(b^2*a') > n;
//! @author Kirill Shcherbatov <kshcherbatov@gmail.com>, 376 group, DCAM MIPT
//! @version 1.0
//! @note Task B, varriant 2, test 2007, MIPT
//}===================================================================================================

//****************************************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
//****************************************************************************************************


//****************************************************************************************************
#define _EJC
#define PARANOIC_MODE
//****************************************************************************************************

//****************************************************************************************************
//! @def   IS_ZERO
//! @param  value for comparing
//! @note  -Use IS_ZERO to compere float integers with 0
//----------------------------------------------------------------------------------------------------
#define IS_ZERO( value )  ( fabs (value) < DBL_EPSILON )
//****************************************************************************************************

//****************************************************************************************************
//! @def   OUT
//! @note  -Use OUT to print your text in console. It is checking _EJC declaration.
//! @note  -Only if _EJC is defined then the program prints your text.
//! @note  --You also can define _EJC in compilation command (g++ main.cpp -D _EJC)
//----------------------------------------------------------------------------------------------------
#ifdef _EJC
    #define OUT printf
#else
    #define OUT if (0) printf
#endif // _EJC
//****************************************************************************************************


//****************************************************************************************************
//! @def    VALID
//! @param  CONDITIONAL for checking
//! @param  MESSAGE for displaying if CONDITIONAL is false
//! @note   -It checks the validity of the expression.
//! @note   -Program will use OUT to display MESSAGE
//! @note   -If sended conditional is false, program will be terminated sending 1 message
//----------------------------------------------------------------------------------------------------
#ifdef  PARANOIC_MODE
    #define VALID( CONDITIONAL, MESSAGE )       \
    if (!(CONDITIONAL))                         \
    {                                           \
        OUT  ( MESSAGE );                       \
        exit ( 1 );                             \
    } // VALID in PARANOIC_MODE
#else
    #define VALID( CONDITIONAL, MESSAGE ) \
    CONDITIONAL;
#endif
//****************************************************************************************************

//****************************************************************************************************
//! @def    CHECK
//! @param  CONDITIONAL for checking
//! @param  MESSAGE for displaying if CONDITIONAL is false
//! @note   -It checks the validity of the expression.
//! @note   -Program will use OUT to display MESSAGE
//! @note   -If sended conditional is false, program will be terminated sending 1 message
//! @warning   IN RELIASE MODE IT WILL BE REMOOVED
//----------------------------------------------------------------------------------------------------
#ifdef PARANOIC_MODE
    #define CHECK( CONDITIONAL, MESSAGE )       \
    if (!(CONDITIONAL))                         \
    {                                           \
        OUT  ( MESSAGE );                       \
        exit ( 1 );                            \
    } // CHECK in PARANOIC_MODE
#else
    #define CHECK( CONDITIONAL, MESSAGE )
#endif
//****************************************************************************************************

//****************************************************************************************************
int normalize ( long long unsigned int n,
                long long unsigned int * b, long long unsigned int * a);
//****************************************************************************************************

//****************************************************************************************************
//! @param - number of sending arguments
//! @param argv[] - arguments, include generated by OS
//! @return 0 on success
//----------------------------------------------------------------------------------------------------
int main(int, const char* argv[])
{
    OUT ( "%s (%s) %s %s:\n\n", argv[ 0 ], __FILE__, __DATE__, __TIME__ );
    OUT ( "#Programm for n&[1; 2^32) integer \"normalizing\"\n"
            "#presentation it as b*sqrt(a), Yb' > b : sqrt(b^2*a') > n\n" );

    const long long unsigned int SUPRENUM = 1llu << 32;

    OUT ( "#Enter n, integer for \"normalizing\"\n"
          "#n = ");

    long long unsigned n = 0;

    VALID ( scanf("%llu",&n) == 1 , "#Problems with inputed n. Read the instructions above & try again.\n" );

    CHECK ( n > 0 ,  "#Inputed N is incorrect. N should be greater than 0.\n" );
    CHECK ( n < SUPRENUM , "#Inputed N is incorrect. N should be lower than 2^32.\n");

    long long unsigned b = 0, a = 0;

    VALID ( normalize (n, &b,&a) == 0, "#Sorry, it looks like bug in a programm code in function normalize(),"
                                        "please report the developer..\n")

    OUT ("#Ok, %d = sqrt( ",n);
    printf ("%llu ",a);
    OUT (" ) * ");
    printf ("%llu\n",b);

    return 0;
}
//****************************************************************************************************

//****************************************************************************************************
//! @param integer for normalize
//! @param out first parameter, integer staying in sqrt()
//! @param out first parameter, integer multipling on sqrt()
//! @return 0 on success
//----------------------------------------------------------------------------------------------------
int normalize ( long long unsigned int n,
                long long unsigned int * b, long long unsigned int * a)
{
    CHECK(b!=NULL, "b value is NULL!\n"); CHECK(a!=NULL, "a value is NULL!\n");

    register long long unsigned int max_b=n;
    while (!IS_ZERO (sqrt (max_b) - (int)sqrt (max_b) ) || !IS_ZERO (n - (int)(n / max_b)* max_b)) max_b--;
    *b=(int)sqrt(max_b);
    *a=(int)(n / max_b);
    return 0;
}

//****************************************************************************************************
